/********************************************************************************************************************************
 * 《C ++ Primer》第五版中文版，读书笔记：按照书中的的示例源码和每一个小章节的课后习题，自己动手写代码实现，作为联系和测试。
 * Date: 2024-03-29 09:33
 * Author: dimon.chen 
 * EMali: 1181302388@qq.com 
 * 
 * 章节:  第三章 字符串，向量和数组
 *       标准库类型 string
 *       标准库类型 vector
 *       内置类型数组
 *       3.2 string 类型初始化
 *       3.2.2 string对象上的操作
 * 
 ********************************************************************************************************************************/

/// 标准库类型string
///
///

#include <iostream>
#include <string>           //标准库类型string，使用库类型string必须包含头文件 string
                            //string定义在命名空间std，需要使用作用域运算符 std:: 指明使用来自命名空间std中的名字string
                            //

using std::cin;             //using声明
using std::cout;            //每个名字都需要独立的using声明
using std::endl;

int main(int argc, char *argv[])
{
    ///
    /// 3.2.2 节练习
    /// 练习3.2：编写一段程序从标准输入中依次读入一整行，然后修改该程序使其一次读入一个单词
    ///

    std::string line;       //默认初始化，string对象line是一个空串

    //getline()的返回结果为它的参数 istream 对象，getline()喊出从标准输入中读入一行包括空白字符，直到遇到换行符就结束（也读入换行符）
    //把读入的字符串存到参数string对象（除换行符外）
    //getline实际上丢弃了读入的换行符
    //getline在第读取第一个字符就遇到换行符时，就停止读取，这时候读取到一个空的string对象，并存入到参数中，得到的参数就是空string对象，一个空串
    while(getline(cin, line)){
        if(!line.empty()){
            cout << "you enter line: " << line << endl;

            if(line == "bye"){          //C++标准库允许字符字面值和字符串字面值自动转换为string对象
                break;
            }
        }
            
        else
            cout << "you enter line is empty" << endl;
    }


    //如何初始化类的对象是由类本身决定的。一个类可以定义多种初始化类对象的方式，只不过只写方式需要有所不同：或者是参数的数量不同，或者是参数的类型不同
    //使用标准库string类型，必须包含头文件 string

    //string 类和其它大多数标准库类型都定义了几种配套的类型。这些配套类型体现了标准库的与机器无关性。如 size_type 是可类型string定义的配套类型，实际使用时使用
    //作用域操作符（::）来表明名字 size_type 是在类 string 中定义的。

    //
    //cin >> 输入运算符每次读取一个单词，遇到空格是结束，并且会忽略开头的空白字符
    while(cin >> line){
        std::string::size_type len = line.size();
        cout << "you enter line: " << line << " size is " << len << endl;
        if(len > 10){
            break;
        }
    }

    ///
    /// 3.2.2 节练习
    /// 练习3.3：请说明string类的输入运算符和getline函数分别是如何处理空白字符的。
    /// 
    // string 类的输入运算符（>>），从运算符右侧的流istream对象中读取一个单词，并存入运算符左侧的string对象。
    // string 类的输入运算符会忽略起始的空白字符（如空格，tab制表符，换行符）等，从第一个非空白字符开始读取，遇到空白字符结束
    // string 类的输入运算符返回其左侧的流对象
    // geline() 函数有两个参数，一个是输入流对象is，一个是 string对象，getline()函数从输入流istream对象中一次读取一行并保留空白字符，
    // 遇到换行符时getline函数读取结束（包括换行符），getline()从输入流中读取一个string对象并存入到参数string s，
    // getline函数实际上丢弃掉了输入的换行符
    // getline的返回结果为其参数istream对象


    ///
    /// 3.2.2 节练习
    /// 练习3.4：编写一个程序读入两个字符，比较其是否相等并输入结果。如果不相等，输出较大的那个字符串。改写尚明程序比较输入的两个字符串是否
    /// 等长，如果不等长，输出长度较大的字符串。
    /// 

    cout << "Please enter two string:" << endl;
    std::string line2;    //默认初始化，一个空string对象，一个空串


    //读取之前的剩余换行符
    getline(cin, line);

    cout << "Line1: ";
    getline(cin, line);
    cout << "Line2: ";
    getline(cin, line2);

    //string对象 == 运算符
    if(line == line2){
        cout << "the string you enter is equal " << "line1: " << line << " line2: " << line2 << endl;
    }
    else{
        cout << "the string you enter is not equal " << "line1: " << line << " line2: " << line2 << endl;
        if(line > line2)
            cout << "line1 is the larger one: " << line << endl;
        else
            cout << "line2 is the larger one: " << line2 << endl;
    }



    ///
    /// 3.2.2 节练习
    /// 练习3.4：编写一个程序从标注输入中读入多个字符串并将它们连接在一起，输出连接成的大字符串。然后修改上述程序，用空格把输入多个字符串连接起来
    /// 
    ///

    std::string sum;        //默认初始化，一个空string对象，一个空串
    while(cin >> line){
        sum += line + " ";          //string对象符合赋值运算符，等价于 sum = sum + line
                                    //字符串字面值可以自动转换为string对象
    }
    cout << "the total string you enter is: " << sum << endl;


    //string对象的size函数和empty函数
    //s.size()的返回值类型是 string::size_type，它是一个 unsigned类型
    //s.empty()返回值是bool布尔类型
    //string类和大多数其他标准库类型都定义了几种配套类型。这些配套类型体现了标准库与机器无关的特性。
    //size_type就是其中的一种。实际使用时，使用作用域操作符（::）来表名名字size_type是定义在string类中。

    return 0;
}